//== SAGITTARIUS ============================================================================

//== FILEDOC =========================================================================

/** @file CUnicode.h
  * @brief Contains C interface to UTF-8 encoding and decoding routines
  */

//== BEGINNING OF CODE ===============================================================

#ifndef __SAGITTARIUS__CUNICODE__H_
#define __SAGITTARIUS__CUNICODE__H_

//== INCLUDES ========================================================================

#include "sagittarius/core/SagittariusCore.h"

#include <stdio.h>


#ifdef __cplusplus
extern "C" {
#endif

/**
  * @brief Machine word to hold Unicode codepoint (must be able to hold largest allowed codepoint)
  */
typedef unsigned int UnicodeCChar;

/** @fn  int UTF8_ConvertBuffer(const char* in, UnicodeCChar* out)
  * @brief Decode the buffer
  * @return The total number of converted characters
  * @param[in] in Raw byte stream
  * @param[out] out Output codepoint buffer; must be large enough to accommodate all potential chars in the input
  * @par Description
  * Converts null-terminated UTF8 buffer into Unicode codepoint representation.  
  * The output buffer must be at least 4x the size of the input buffer in bytes 
  * (including the null character - the output buffer is also null-terminated).
**/
int UTF8_ConvertBuffer(const char* in, UnicodeCChar* out);

/** @fn  int UCEncode(const UnicodeCChar* buf, char* out)
  * @brief Encode the buffer
  * @return The total number of (decoded?) characters
  * @param[in] buf Unicode codepoint buffer
  * @param[out] out Encoded byte stream; must be large enough to accommodate encoded bytes
  * @par Description
  * Converts null-terminated sequence of codepoint values (block of type @ref UnicodeCChar)
  * into a UTF-8 bytestream.
  * The required size of the output buffer for a given input can be determined 
  * via @ref UCBufferLen
**/
int UCEncode(const UnicodeCChar* buf, char* out);

/** @param[in] buf    Decoded buffer
  * @brief Print the decoded buffer
**/
int printUnicodeBuf(const UnicodeCChar* buf);

/** @param[in] stream The stream to use
  * @param[in] buf    Decoded buffer
  * @param[in] l      The length of the decoded buffer
  * @brief Print the decoded buffer of length @a l
**/
int fprintUnicodeBufl(FILE* stream, const UnicodeCChar* buf, const int l);

/** @return The number of bytes occuped by the encoded version of @a chr
  * @param[in] chr Unicode codepoint
  * @brief Get the number of bytes required for a codepoint's representation
**/
int UCgetNBytes(UnicodeCChar chr);

/**
 * @fn  UnicodeCChar* UTF8_ShrinkBuffer(UnicodeCChar* buf, size_t new_size)
 * @return The new buffer
  * @param[in] buf Original buffer
  * @param[in] new_size Desired size
 * @par Description
 * Shrinks the buffer to the size specified.
 * This is useful, for example, when the buffer is preemtively
 * allocated to a larger size than ultimately necessary.
 * Because the number of DWORDS (i.e. the true number of 
 * characters in the bitstream) cannot be known ahead of
 * time, the buffer must be allocated to 4x the size of
 * the input buffer. If the input stream contains multi-byte
 * characters, this will be an over-estimate. To obtain the 
 * minimum size, use the return value of @ref UTF8_ConvertBuffer
 * NOTE: old buffer is freed
   **/
UnicodeCChar* UTF8_ShrinkBuffer(UnicodeCChar* buf, size_t new_size);

/** @returns The total length of the hypothetical UTF-8 @a encoded buffer including the null character
  * @param[in] buf The decoded buffer
  * @brief Get encoded UTF-8 buffer length including null-terminating char
  */
size_t UCBufferLen(const UnicodeCChar* buf);

/** @returns The total length of the hypothetical UTF-8 @a encoded buffer including the null character
  * @param[in] buf The decoded buffer
  * @brief Get encoded UTF-8 buffer length including null-terminating char
  */
size_t UC_UTF8BufferLen(const UnicodeCChar* buf);

//Constants
/** @brief The value assumed by the null character (should be zero) */
#define UC_Null 0

///-- Assembly Routines --
/*#if SAGITTARIUS_ARCH == GAIA_ARCH_64
    extern int UTF8_ConvertBuffer_x86_64(const char* in, UnicodeCChar* out);
    #define UTF8_ASM_PRIMITIVE UTF8_ConvertBuffer_x86_64
#else
    //#error "No low-level unicode routines specified for 32 bit platform"
#endif

#if SAGITTARIUS_UTF8_USE_ASM_ROUTINES
    #define UTF8_CONVERT_BUFFER_PRIMITIVE UTF8_ASM_PRIMITIVE
#else
    #define UTF8_CONVERT_BUFFER_PRIMITIVE UTF8_ConvertBuffer //C version
#endif*/

#ifdef __cplusplus
}//extern "C"
#endif

#endif
